#pragma pack(1)
#include <stdio.h>
#include <string.h>
#include "HF_Lib.h"
#include "UT_DM_Defines.h"
#include "CFM_Lib.h"
#include <stdlib.h>


relDesc NewRelDesc ( char *relname, int relwidth, int attrcnt, int indexcnt );
attrDesc NewAttrDesc ( char *relname, char *attrname, int offset, int attrlenght, char attrtype, int indexed, int indexno );

int CFM_Create ( void )
{
	int relcatDesc, attrcatDesc;
	relDesc my_relcat;
	attrDesc my_attrcat;
	
	/* Δημιουργία και αρχικοποίηση του πίνακα relcat. 
	 *Αυτό προυποθέτει δημιουργία των αρείων για την αναπαράσταση των
	 *πινάκων σστον δίσκο καθώς και δημιουργία και αποθήκευση της πληροφορίας
	 *των πινάκων στα αντίστοιχα αρχεία.
	 */
	
	/* Δημιουργία, άνοιγμα και εισαγωγή των εγγραφών για των πίνακα relcat. */

	/* Δημιουργία. */

	if ( ( relcatDesc = HF_CreateFile("relcat") ) < 0 )
	{													
		HF_PrintError("Error in CFM Create");			
		return UTE_errno =  UTE_HF_ERROR;
	}
	
	/* Άνοιγμα. */

	if ( ( relcatDesc = HF_OpenFile("relcat") ) < 0 )
	{
		HF_PrintError("Error in CFM Create");
		return UTE_errno =  UTE_HF_ERROR;
	}

	/* Δημιουργία και εισαγωγή της πληροφορίας για τον relcat, στον relcat. */

	my_relcat = NewRelDesc ( "relcat", sizeof(relDesc), 4, 0 );
	
	if(( UTE_errno = HF_InsertRec(relcatDesc, (char *) &my_relcat, sizeof(relDesc)) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Δημιουργία και εισαγωγή της πληροφορίας για τον attrcat, στον relcat. */

	my_relcat = NewRelDesc ( "attrcat", sizeof(attrDesc), 7, 0 );

	if(( UTE_errno = HF_InsertRec(relcatDesc, (char *) &my_relcat, sizeof(relDesc)) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Κλείσιμο του relcat. */
	if ( ( UTE_errno = HF_CloseFile(relcatDesc) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");
		return UTE_errno = UTE_HF_ERROR;
	}
		
	/* Δημιουργία και αρχικοποίηση του πίνακα attrcat. 
	 *Αυτό προυποθέτει δημιουργία των αρείων για την αναπαράσταση των
	 *πινάκων σστον δίσκο καθώς και δημιουργία και αποθήκευση της πληροφορίας
	 *των πινάκων στα αντίστοιχα αρχεία.
	 */

	/* Δημιουργία. */

	if ( ( attrcatDesc = HF_CreateFile("attrcat") ) < 0 )
	{
		HF_PrintError("Error in CFM Create");
		return UTE_errno =  UTE_HF_ERROR;
	}

	/* Άνοιγμα.*/
	
	if(( relcatDesc = HF_OpenFile("attrcat")) < 0 )
	{
		HF_PrintError("Error in CFM Create");			
		return UTE_errno =  UTE_HF_ERROR;
	}
		
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute relname, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "relname", 0, MAXNAME, 'c', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute attrname, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "attrname", MAXNAME, MAXNAME, 'c', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute offset, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "offset", 2 * MAXNAME, sizeof(int), 'i', 0, -1 );
		
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute attrlenght, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "attrlegth", 2 * MAXNAME + sizeof(int), sizeof(int), 'i', 0, -1 );

	if ( ( UTE_errno = HF_InsertRec ( attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute attrtype, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "attrtype", 2 * MAXNAME + 2 * sizeof(int), sizeof(char), 'c', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc)) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute indexed, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "indexed", 2 * MAXNAME + 2 * sizeof(int) + sizeof(char), sizeof(int), 'i', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute indexno, στον attrcat. */

	my_attrcat = NewAttrDesc ( "attrcat", "indexno", 2 * MAXNAME + 3 * sizeof(int) + sizeof(char), sizeof(int), 'i', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
		
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute relname του relcat, στον attrcat. */

	my_attrcat = NewAttrDesc ( "relcat", "relname", 0, MAXNAME, 'c', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute relwidth του relcat, στον attrcat. */

	my_attrcat = NewAttrDesc ( "relcat", "relwidth", MAXNAME, sizeof(int), 'i', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute attrcnt του relcat, στον attrcat. */

	my_attrcat = NewAttrDesc ( "relcat", "attrcnt", MAXNAME + sizeof(int), sizeof(int), 'i', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Δημιουργία και εισαγωγή της πληροφορίας για το attribute indexcnt του relcat, στον attrcat. */

	my_attrcat = NewAttrDesc ( "relcat", "indexcnt", MAXNAME + 2 * sizeof(int), sizeof(int), 'i', 0, -1 );
	
	if ( ( UTE_errno = HF_InsertRec(attrcatDesc, (char *) &my_attrcat, sizeof(attrDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");		
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Κλείσιμο του αρχείου για τον πίνακα attrcat. */
	
	if ( ( UTE_errno = HF_CloseFile(attrcatDesc) ) < 0 )
	{
		HF_PrintError("Error in CFM Create");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	return UTE_errno = UTE_OK;
}

int CFM_AddRel ( relDesc rel, attrDesc * attrs )
{
	int i;
	//printf("We will insert relationship with: relwidht %d, attrcount %d, name %s \n",rel.relwidth, rel.attrcnt, rel.relname);
	/* Ενημέρωση του πίνακα relcat για την δημιουργία της σχέσης rel */

	//printf(" reldesc %s \n", (char *) &rel); 
	if ( ( UTE_errno = HF_InsertRec ( relCatFd, (char *) &rel, sizeof(relDesc) ) ) < 0 )
	{
		HF_PrintError("Error in CFM AddRel");
		return UTE_errno = UTE_HF_ERROR;
	}	
	//create malakes(ena =  'f', dio = 'i', tria='c25');
	/* Για όλα τα attruibutes της σχέσης ενημερώνω τον πίνακα attrcat. */

	for ( i = 0; i < rel.attrcnt; i++ )
	{
		//printf("Inserting attr with relname = %s  , attrname = %s,   offset = %d, attrlength = %d, type = %c\n",attrs[i].relname, attrs[i].attrname, attrs[i].offset, attrs[i].attrlength, attrs[i].attrtype);
		if ( ( UTE_errno = HF_InsertRec ( attrCatFd, (char *) &attrs[i], sizeof(attrDesc) ) ) < 0 )
		{
			HF_PrintError("Error in CFM AddRel");
			return UTE_errno = UTE_HF_ERROR;
		}
	}

	return UTE_errno = UTE_OK;
}

int CFM_DeleteRel ( char * relName )
{
	relDesc reldesc;
	attrDesc attrdesc;	
	int scanDesc, recId, i;
	
	/* Άνοιγμα του scan για να βρούμε την καταχώρηση για την σχέση στον
	 *πίνακα relcat.
	 */

	scanDesc = HF_OpenFileScan ( relCatFd, sizeof(relDesc), 'c', MAXNAME, 0, EQUAL, relName );
	
	if ( scanDesc < 0 )
	{
		HF_PrintError ( "error in Delete Rel" );
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Προσκόμησή της.*/
printf("Going to delete rec with name: %s\n", relName);
	recId = HF_FindNextRec ( scanDesc, (char *) &reldesc );

	if ( recId < 0 )
	{
		HF_PrintError("error in Delete Rel");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Διαγραφή της εγγραφής. */

	if ( ( UTE_errno = HF_DeleteRec ( relCatFd, recId, sizeof(relDesc) ) ) < 0 )
	{
		HF_PrintError("error in Delete Rel");
		return UTE_errno = UTE_HF_ERROR;
	}
		
	/* Κλείσιμο του scan που ανοίξαμε πριν. */

	if ( ( UTE_errno = HF_CloseFileScan(scanDesc) ) < 0 )
	{
		HF_PrintError("Error in Delete Rel");
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Άνοιγμα του scan για να βρούμε τις καταχωρήσεις των attributes
	 *για την σχέση στον πίνακα attrcat.
	 */

	scanDesc = HF_OpenFileScan ( attrCatFd, sizeof(attrDesc), 'c', MAXNAME, 0, EQUAL, relName );
	
	if ( scanDesc < 0 )
	{
		HF_PrintError("error in Delete Rel");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Προσκόμηση εγγραφών απο το scan και διαγραφή των εγγραφών. */

	for ( i = 0; i < reldesc.attrcnt; i++ )
	{
		recId = HF_FindNextRec(scanDesc, (char *) &attrdesc);
		
		if( recId < 0 )
		{
			HF_PrintError("error in Delete Rel");
			return UTE_errno = UTE_HF_ERROR;
		}
		
		if ( ( UTE_errno = HF_DeleteRec(attrCatFd, recId, sizeof(attrDesc) ) ) < 0 )
		{
			HF_PrintError("error in Delete Rel");
			return UTE_errno = UTE_HF_ERROR;
		}
		
	}
	
	/* Κλείσιμο του scan που ανοίξαμε για την ενημέρωση του attrcat. */

	if ( ( UTE_errno = HF_CloseFileScan(scanDesc) ) < 0 )
	{
		HF_PrintError("Error in Delete Rel");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	return UTE_OK;
}

int CFM_IndexAttribute ( char *relName, char *attrName, int indexNo )
{
	int scanDesc, recId, i;
	relDesc reldesc;
	attrDesc attrdesc;
	
	/* Άνοιγμα scan για να βρούμε το attibute που θέλουμε να ευρετισιάσουμε. */

	scanDesc = HF_OpenFileScan ( relCatFd, sizeof(relDesc), 'c', MAXNAME, 0, EQUAL, relName );
	
	if ( scanDesc < 0 )
	{
		HF_PrintError("error in Index Attribute");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Προσκόμηση της εγγραφής στη μνήμη και διαγραφή της απο τον δίσκο. */

	recId = HF_FindNextRec ( scanDesc, (char *) &reldesc );
	
	if ( recId < 0 )
	{
		HF_PrintError("error in Index Attribute");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	if ( ( UTE_errno = HF_DeleteRec(relCatFd, recId, sizeof(relDesc) ) ) < 0 )
	{
		HF_PrintError("error in Index Attribute");
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Ενημέρωση της εγγραφής για τον πίνακα relcat που αντιστοιχεί για την σχέση relname
	 *ότι προστέθηκε ένα ακόμα ευρετήριο σε κάποιο απο τα attributes της.
	 */

	reldesc.indexcnt++;

	/* Εισαγωγή της ενημερωμένης εγγραφής στο αρχείο. */

	if ( ( UTE_errno = HF_InsertRec(relCatFd, (char *) & reldesc, sizeof(relDesc) ) ) < 0 )
	{
		HF_PrintError("error in Index Attribute");
		return UTE_errno = UTE_HF_ERROR;
	}
		
	/* Κλείσιμο του scan που ανοίξαμε για να βρούμε την εγγραφή για τον relname πίνακα 
	 *στον relcat
	 */

	if ( ( UTE_errno = HF_CloseFileScan(scanDesc) ) < 0 )
	{
		HF_PrintError("Error in Index Attribute");
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Εύρεση της εγγραφής στον attrcat που ανήκουν στον πίνακα με όνομα relname. */	

	scanDesc = HF_OpenFileScan ( attrCatFd, sizeof(attrDesc), 'c', MAXNAME, 0, EQUAL, relName );
	
	if ( scanDesc < 0 )
	{
		HF_PrintError("error in Delete Rel");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	/* Προσπέλαση των εγγραφών του scan για να βρούμε αυτή με το όνομα attrname. */

	for ( i = 0; i < reldesc.attrcnt; i++ )
	{
		recId = HF_FindNextRec ( scanDesc, (char *) &attrdesc );
		
		if ( recId < 0 )
		{
			HF_PrintError("error in Delete Rel");
			return UTE_errno = UTE_HF_ERROR;
		}
		
		if ( strcmp ( attrdesc.attrname, attrName ) == 0 )
		{
			/* Αν βρέθηκε η εγγραφή, την διαγράφουμε αφού την φέρομε στη μνήμη
			 *την ευρετηριάζουμε και την ξαναγράφουμε στο δίσκο.
			 */

			if ( ( UTE_errno = HF_DeleteRec(attrCatFd, recId, sizeof(attrDesc) ) ) < 0 )
			{
				HF_PrintError("error in Delete Rel");
				return UTE_errno = UTE_HF_ERROR;
			}
	
			/* Αν το attibute είναι ήδη ευρετηριασμένο, επιστροφή λαθους. */

			if ( attrdesc.indexed == 1 )
			{
				return UTE_errno = CFME_INDEXED;
			}

			attrdesc.indexno = indexNo;
			attrdesc.indexed = 1;

			if ( ( UTE_errno = HF_InsertRec(attrCatFd, (char *) & attrdesc, sizeof(attrDesc) ) )< 0 )
			{
				HF_PrintError("error in Index Attribute");
				return UTE_errno = UTE_HF_ERROR;
			}

			if ( ( UTE_errno = HF_CloseFileScan(scanDesc) ) < 0 )
			{
				HF_PrintError("Error in Delete Rel");
				return UTE_errno = UTE_HF_ERROR;
			}

			return UTE_errno = UTE_OK;
		}
	}
	
	/* Αν η ροή του ελέγχου φτάσει εδώ, σημαίνει πως τερμάτησε η for χωρίς
	 *να επιστρέψει η συνάρτηση, επομένως και δνε βρέθηκε το attribute.
	 */

	return UTE_errno = UTE_NOT_FOUND;		
}

int CFM_Lookup ( char *relName, relDesc *rel, attrDesc **attrs )
{
	int scanDesc, recId, i;

	/* Άνοιγμα scan για να βρούμε την εγγραφή με όνομα relname στον
	 * πίνακα relcat, με στόχο να προσκομήσουμε απαραίτητες πληροφορίες για
	 *την εκτέλεση της CFM_Lookup.
	 */

	scanDesc = HF_OpenFileScan ( relCatFd, sizeof(relDesc), 'c', MAXNAME, 0, EQUAL, relName );
	
	if ( scanDesc < 0 )
	{
		HF_PrintError("error in Lookup");
		return UTE_errno = scanDesc;
	}
	
	/* Προσκόμηση της εγγραφής. */

	recId = HF_FindNextRec ( scanDesc, (char *) rel );
	
	if ( recId < 0 )
	{
		HF_PrintError("error in Lookup");
		return UTE_errno = recId;
	}
	
	HF_CloseFileScan (scanDesc);
	*attrs = malloc ( sizeof(attrDesc) * rel->attrcnt );

	//for ( i = 0; i < rel->attrcnt; i++ )
	//{
	//	attrs[i] = malloc ( sizeof(attrDesc) );
	//}
		
	/* Άνοιγμα scan για την προσκόμηση των εγγραφών για τα attributes του πίνακα relname. */

	scanDesc = HF_OpenFileScan ( attrCatFd, sizeof(attrDesc), 'c', MAXNAME, 0, EQUAL, relName );
	
	if ( scanDesc < 0 )
	{
		HF_PrintError("error in Lookup");
		return UTE_errno = scanDesc;
	}
	
	for ( i = 0; i < rel->attrcnt; i++ )
	{		
		/* Προσκόμηση όλων των εγγραφών που αφορούν τον relnamec πίνακα στον πίνακα attrs. */

		if ( recId < 0 )
		{
			HF_PrintError("error in Lookup");
			return UTE_errno = UTE_HF_ERROR;
		}

		recId = HF_FindNextRec ( scanDesc, (char *) (*attrs + i) );
	}
	HF_CloseFileScan (scanDesc);
	return UTE_errno = UTE_OK;
}

attrDesc NewAttrDesc ( char *relname, char *attrname, int offset, int attrlenght, char attrtype, int indexed, int indexno )
{
	attrDesc newAttrDesc;

	strncpy ( newAttrDesc.relname , relname, MAXNAME );
	strncpy ( newAttrDesc.attrname, attrname, MAXNAME );
	newAttrDesc.offset = offset;
	newAttrDesc.attrlength = attrlenght;
	newAttrDesc.attrtype = attrtype;
	newAttrDesc.indexed = indexed;
	newAttrDesc.indexno = indexno;
	return newAttrDesc;
}

relDesc NewRelDesc ( char *relname, int relwidth, int attrcnt, int indexcnt )
{
	relDesc newRelDesc;
	strncpy ( newRelDesc.relname, relname, MAXNAME );
	newRelDesc.relwidth = relwidth;
	newRelDesc.attrcnt = attrcnt;
	newRelDesc.indexcnt = indexcnt;
	return newRelDesc;
}

